package org.javahispano.javacup.tacticas_aceptadas.fpena.org.tricolor;

import org.javahispano.javacup.tacticas_aceptadas.fpena.org.tricolor.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.TacticaDetalle;

public class TacticaTricolor implements Tactica {

    private DecimalFormat df = new DecimalFormat();

    Posicion normal[] = null;

    Posicion posicionNeutra[]=new Posicion[]{

        new Posicion(0.23776223776223776,-50.83710407239819),
        new Posicion(-13.314685314685315,-26.606334841628957),
        new Posicion(-5.944055944055944,-32.782805429864254),
        new Posicion(4.755244755244756,-33.49547511312217),
        new Posicion(14.503496503496503,-26.84389140271493),
        new Posicion(-24.251748251748253,-9.027149321266968),
        new Posicion(-0.951048951048951,10.47511312217194573),
        new Posicion(23.538461538461537,-9.264705882352942),
        new Posicion(-23.062937062937063,25.656108597285066),
        new Posicion(0.4755244755244755,30.90497737556561),
        new Posicion(23.538461538461537,24.705882352941178)
    };

    Posicion posicionAtaque[]=new Posicion[]{
        new Posicion(0,-50.83710407239819),
        new Posicion(-13.314685314685315,-15.606334841628957),
        new Posicion(-5.944055944055944,-20.782805429864254),
        new Posicion(4.755244755244756,-20.49547511312217),
        new Posicion(14.503496503496503,-15.84389140271493),
        new Posicion(-24.251748251748253,0.027149321266968),
        new Posicion(-0.951048951048951,15.47511312217194573),
        new Posicion(23.538461538461537,0.264705882352942),
        new Posicion(-15,32),
        new Posicion(0,45),
        new Posicion(15,33)
    };

    private Posicion recibiendo[] = new Posicion[]{
        new Posicion(0.1, -50),
        new Posicion(-13, -30),
        new Posicion(-3, -35),
        new Posicion(3, -35),
        new Posicion(13, -30),
        new Posicion(-16, -14),
        new Posicion(0.1, -16),
        new Posicion(16, -14),
        new Posicion(-10, -1),
        new Posicion(0.1, -10),
        new Posicion(10, -1)
    };

    private Posicion sacando[] = new Posicion[]{
        new Posicion(0.1, -50),
        new Posicion(-13, -30),
        new Posicion(-3, -33),
        new Posicion(3, -33),
        new Posicion(13, -30),
        new Posicion(-16, -14),
        new Posicion(0.1, -16),
        new Posicion(16, -14),
        new Posicion(-2, -0.5),
        new Posicion(0.1, -10),
        new Posicion(3, -1)
    };
    private int masCercano = -1;
    private int masCercanoConMenorY = -1;
    private Posicion posicionAtras = new Posicion();
    private Balon balonAnterior = new Balon();
    private Balon balonSiguiente = new Balon();
    private ArrayList<Balon> posicionesFuturo;
    private SituacionPartido sp;
    private double yMaximoGolero = (-1 * (Constantes.LARGO_CAMPO_JUEGO / 2)) + Constantes.ANCHO_AREA_CHICA + 3; //no sale del area
    private double xMaximoGolero = Constantes.LARGO_AREA_CHICA;// + 3; //no sale del area

    private double yAreaGrande = (-1 * (Constantes.LARGO_CAMPO_JUEGO / 2)) + Constantes.ANCHO_AREA_GRANDE;
    private List<Comando> comandos = new ArrayList<Comando>();
    int[][] ultimosDosJugadores = new int[][]{{-1, 0}, {-1, 0}};
    private boolean iteracionFound = false;
    private double altura = 0;
    private boolean suelo = false;
    private double dz = 0;
    private boolean defensa = false;
    private boolean ataque = true;

    public TacticaTricolor() {
        df.setMaximumFractionDigits(4);
    }

    public TacticaDetalle getDetalle() {
        return new TacticaDetalleTricolor();
    }

    public Posicion[] getPosicionSaca(SituacionPartido sp) {

        balonAnterior = new Balon();
        balonSiguiente = new Balon();
        return sacando;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
        balonAnterior = new Balon();
        balonSiguiente = new Balon();
        return recibiendo;
    }

    private void cambiarPosiciones (int jugadorA, int jugadorB){
        Posicion tmp = posicionAtaque[jugadorA];
        posicionAtaque[jugadorA] = new Posicion(posicionAtaque[jugadorB]);
        posicionAtaque[jugadorB] = new Posicion(tmp);

        tmp = posicionNeutra[jugadorA];
        posicionNeutra[jugadorA] = new Posicion(posicionNeutra[jugadorB]);
        posicionNeutra[jugadorB] = new Posicion(tmp);
    }

    public List<Comando> ejecutar(SituacionPartido arg) {

        if (arg.iteracion() % 300 == 0){
            cambiarPosiciones (8, 10);
            cambiarPosiciones (5, 7);
        }
        comandos.clear();
        sp = arg;
        ataque = true;
        if (sp.balon().getY() < 0){
            ataque = false;
        }
        if (sp.golesPropios() > sp.golesRival()){
            ataque = false;
        }

        normal = posicionNeutra;
        if ((sp.saco() && sp.balon().getY()>15) || ataque){
            normal = posicionAtaque;
        }

        iteracionFound = evitarCicloDePases();
        if (iteracionFound) {
            if (sp.golesPropios() > sp.golesRival() + 2) { //que quede trancado igual
                iteracionFound = false;
            }
        }

        if (sp.sacaRival() || sp.saco()) {
            balonAnterior.dz = 0;
            balonSiguiente.dz = 0;
            suelo=false;
        }
        if (balonAnterior.altura == 0 && sp.alturaBalon() == 0) {
            balonAnterior.dz = 0;
            balonSiguiente.dz = 0;
            suelo=false;
        }
        altura = sp.alturaBalon();
        if (Math.abs (posicionAtras.angulo(balonAnterior.posicion) - balonAnterior.posicion.angulo(sp.balon())) > 0.00001){
            dz = Constantes.VELOCIDAD_INICIAL_VERTICAL; //TODO: esto ya no es asi
            suelo = false;
            Balon temp = Util.getSiguienteUbicacion(balonAnterior.posicion, sp.balon(), altura, dz, suelo);
            altura = temp.altura;
            dz = temp.dz;
            suelo = temp.suelo;
        }

        actualizarPosiciones();
        balonSiguiente = posicionesFuturo.get(0);

        masCercano = elMasCercanoAlBalon(-1);
        masCercanoConMenorY = elMasCercanoAlBalon(balonSiguiente.posicion.getY());

        moverGolero();

        if (sp.balon().getY() > 0) {
            defensa = false;
        } else if (sp.sacaRival()) {
            defensa = true;
        }

        ArrayList<Integer> excluir = new ArrayList<Integer>();
        HashMap<Integer, Integer> cantidadMarcas = new HashMap();//2 no lo marca nadie, 1 lo marca 1, 0 van 2 a marcar si pueden
        for (int i = 0; i < 11; i++) {
            if (sp.rivales()[i].getY() > -10) {
                cantidadMarcas.put(i, 2);
            } else if (sp.rivales()[i].getY() > -25) {
                cantidadMarcas.put(i, 1);//antes decia 2 si estaba en ataque, si no 1
            } else {
                if (defensa){
                    int rivalCercano = Util.getInfoMasCercano(sp.rivales(), sp.balon())[0];
                    if (i == rivalCercano){
                        cantidadMarcas.put(i, 1);
                    }else{
                        cantidadMarcas.put(i, 0);
                    }
                } else {
                    cantidadMarcas.put(i, 1);
                }
            }
        }

        excluir.add(0);
        excluir.add(8);
        excluir.add(9);
        excluir.add(10);

        excluir.add(1);
        excluir.add(3);
        excluir.add(4);
        excluir.add(5);
        excluir.add(6);
        excluir.add(7);

        marcar(2, 2, -1, -1, -25, excluir, cantidadMarcas); //no sube mas de y=-25 a marcar
        excluir.add(2);

        excluir.remove(new Integer(1));
        excluir.remove(new Integer(3));
        excluir.remove(new Integer(4));
        marcar(1, 4, -1, -1, 0, excluir, cantidadMarcas); //estos no suben mas de y=0 a marcar
        excluir.add(1);
        excluir.add(3);
        excluir.add(4);
        excluir.remove(new Integer(5));
        excluir.remove(new Integer(6));
        excluir.remove(new Integer(7));
        marcar(5, 7, -20, -1, 45, excluir, cantidadMarcas); //estos van hasta y=45
        for (int i = 8; i <= 10; i++) {
            if (masCercano == i && !sp.sacaRival() && !sp.saco()) {
                moverJugador(i, cruzarBalon(i));
            } else {
                Posicion nuevaPosicion = null;
                if (i == 9){
                    nuevaPosicion = getPosicionMolestarGolero();
                }else{
                    nuevaPosicion = getPosicionOptima(i);
                }
                if (i == 10 && (sp.iteracion() / 900 % 2 != 0)){
                    if (nuevaPosicion.getX() < 0){
                        nuevaPosicion = new Posicion(nuevaPosicion.getX()+10, nuevaPosicion.getY()+15);
                    }else{
                        nuevaPosicion = new Posicion(nuevaPosicion.getX()-10, nuevaPosicion.getY()+15);
                    }
                }
                moverJugador(i, nuevaPosicion);
            }
        }

        golpearBola();

        posicionAtras = new Posicion(balonAnterior.posicion);
        balonAnterior = new Balon(sp.balon(), sp.alturaBalon(), dz, suelo);

        if (masCercano != -1 && masCercano != 0 && !sp.sacaRival() && !sp.saco()) {
            moverJugador(masCercano, cruzarBalon(masCercano));
        }
        if (masCercano == 0){
            int otroJugador = jugadorConMenorIteracionesSinSerGolero();
            if (otroJugador != -1){
                moverJugador(otroJugador, cruzarBalon(otroJugador));
            }
        }
        if (sp.saco()) {
            if (sp.balon().getY() < 0) {
                moverJugador(masCercano, sp.balon());
            } else {
               int saca = 7;
                if (sp.balon().distancia(sp.misJugadores()[5]) < sp.balon().distancia(sp.misJugadores()[7])){
                    saca = 5;
                }
                moverJugador(saca, sp.balon());
            }
        }
        return comandos;
    }

    private void moverGolero() {

        Posicion moverseA = cruzarBalon(0);
        if ((masCercano == 0) && !sp.sacaRival() && !sp.saco() && moverseA.getY() < yMaximoGolero && Math.abs(moverseA.getX()) <= xMaximoGolero) {
            moverJugador(0, moverseA);
        } else {
            Posicion p = Util.Interseccion(sp.balon(), balonSiguiente.posicion, new Posicion(0, (-1 * Constantes.LARGO_CAMPO_JUEGO / 2)), new Posicion(-20, (-1 * Constantes.LARGO_CAMPO_JUEGO / 2)));
            boolean movi = false;
            if (p != null) {
                if (Math.abs(p.getX()) < (Constantes.LARGO_ARCO / 2)) {
                    moverJugador(0, p);
                    movi = true;
                }
            }

            if (!movi) {
                int x = 0;
                if (balonSiguiente.posicion.getX() < -5) {
                    x = -1;
                } else if (balonSiguiente.posicion.getX() > 5) {
                    x = 1;
                }
                moverJugador(0, new Posicion(x, normal[0].getY()));
            }
        }

        Posicion destino = null;
        destino = reventarBalon(0);
        golpearBalon(0, destino, 1, true);
    }

    public void marcar(int desde, int hasta, double yDefensaDesde, double distanciaMaxima, double yDefensaHasta, ArrayList yaMarcando, HashMap<Integer, Integer> cantidadMarcas) {

        int[] c = ordenarPorMenorY(sp.rivales());
        for (int i = 0; i < c.length - 1; i++) {
            int rival = c[i];
            if ((yDefensaDesde == -1) || sp.rivales()[rival].getY() > yDefensaDesde) {
                if (yDefensaHasta == -1 || sp.rivales()[rival].getY() < yDefensaHasta) {
                    int marcador = getMiJugadorMasCerca(rival, yaMarcando);
                    if (marcador != -1) {
                        if (distanciaMaxima == -1 || (distanciaAlContrario(marcador, rival) < distanciaMaxima)) {

                            if (cantidadMarcas.get(rival) < 2) {
                                yaMarcando.add(marcador);
                                cantidadMarcas.put(rival, cantidadMarcas.get(rival) + 1);
                                boolean adelantamiento = marcoAtras(marcador, rival);
                                Posicion p = getPosicionMarca(rival, getAdelantamientoMarca(adelantamiento));
                                moverJugador(marcador, p);
                            }
                        }
                    }
                }
            }
        }

        for (int i = desde; i <= hasta; i++) {
            if ((masCercano == i || (masCercanoConMenorY == i && balonSiguiente.posicion.getY() < -10)) && !sp.sacaRival() && !sp.saco()) {
                moverJugador(i, cruzarBalon(i));
            } else {
                if (!yaMarcando.contains(i)) {
                    int rival = contrarioMasCercano(i);
                    Posicion p = null;
                    if ((yDefensaHasta == -1 || sp.rivales()[rival].getY() < yDefensaHasta) && cantidadMarcas.get(rival) < 2) {
                        cantidadMarcas.put(rival, cantidadMarcas.get(rival) + 1);
                        boolean adelantamiento = marcoAtras(i, rival);
                        p = getPosicionMarca(rival, getAdelantamientoMarca(adelantamiento));
                    } else {
                        p = getPosicionOptima(i);
                        if (i != 2){
                            if (Util.getInfoMasCercano(sp.rivales(), sp.misJugadores()[i])[1] > 10) { //me dejaron solo veo si puedo subir
                                if (yDefensaHasta == -1 || sp.misJugadores()[i].getY() < yDefensaHasta || i != 3){
                                    //esta linea fue parche de ultimo momento para que puedan subir todo menos el 3 mas haya de su limite
                                    if (sp.misJugadores()[i].getY() + 5 < 40) {
                                        p = sp.misJugadores()[i];
                                        p = p.moverPosicion(0, 5);
                                    }
                                }
                            }
                        }
                    }
                    moverJugador(i, p);
                }
            }
        }
    }

    private boolean marcoAtras(int marcador, int rival) {
        boolean result = false;
        ArrayList excluir = new ArrayList();
        excluir.add(marcador);
        result = Util.getInfoMasCercano(sp.misJugadores(), sp.rivales()[rival], excluir, true)[1] < 5; // adelante y a menos de 5 de distancia
        return result;
    }

    private void golpearBola() {
        for (int i = 1; i < 11; i++) {
            if (puedeSerGol(i)) {
                Posicion destino = getPaloOpuesto();
                double angulo = Util.getAnguloOptimo(sp.balon(), destino, i);
                golpearBalon(i, destino, 1, angulo);
            } else {
                int siguienteJugador = getJugadorPase(i);
                if (siguienteJugador == i) {//autopase
                    Posicion destino = posicionAutoPase(i);
                    if (destino == null) {
                        destino = Constantes.centroArcoSup;
                    }
                    golpearBalon(i, destino, 0.40, false);
                } else if (siguienteJugador != -1) {
                    pasarBalon(i, siguienteJugador);
                } else {
                    if (sp.misJugadores()[i].getY() < 0) { //la reventamos porque no tengo pase
                        int[] c = ordenarPorMenorY(sp.misJugadores());
                        golpearBalon(i, sp.misJugadores()[c[10]], 1, true);
                    } else {
                        golpearBalon(i, Constantes.centroArcoSup, 1, true);
                    }
                }
            }
            //si estoy dentro del area grande la reviento :)
            if ((sp.misJugadores()[i].getY() < yAreaGrande) && (Math.abs(sp.misJugadores()[i].getX()) < Constantes.LARGO_AREA_GRANDE) &&
            (distanciaAlContrarioMasCercano(i)<17)){
                golpearBalon(i, reventarBalon(i), 1, true);
            }
        }
    }

    private void pasarBalon(int jugadorOrigen, int jugadorDestino) {
        boolean marcaAdelante = false; //por defecto asumimos que no tiene marca adelante

        int rival = contrarioMasCercano(jugadorDestino);
        Posicion destino = new Posicion(sp.misJugadores()[jugadorDestino]);
        if (distanciaAlContrario(jugadorDestino, rival) < 10) {
            marcaAdelante = sp.rivales()[rival].getY() < sp.misJugadores()[jugadorDestino].getY();
        }

        if (!marcaAdelante) { //veamos si alguien puede cortar el pase
            marcaAdelante = Util.getDistanciaJugadorMasCercaAlSegmento(sp.rivales(), sp.balon(), destino) < 3;
        }

        if (marcaAdelante) {
            if (sp.misJugadores()[jugadorDestino].getY() > 20) {
                destino = destino.moverPosicion(0, 10);
            } else {
                destino = destino.moverPosicion(0, 15);
            }
            if (!Util.dentroCampo(destino)){
                destino = new Posicion(sp.misJugadores()[jugadorDestino]);
            }
        }
        double distancia = sp.balon().distancia(destino);

        if (distancia < 15) {
            golpearBalon(jugadorOrigen, destino, marcaAdelante ? 0.65 : 1, marcaAdelante);
        } else if (distancia < 23) {
            golpearBalon(jugadorOrigen, destino, marcaAdelante ? 0.75 : 1, marcaAdelante);
        } else if (distancia < 30) {
            golpearBalon(jugadorOrigen, destino, marcaAdelante ? 0.85 : 1, marcaAdelante);
        } else if (distancia < 40) {
            golpearBalon(jugadorOrigen, destino, marcaAdelante ? 0.95 : 1, marcaAdelante);
        } else if (distancia < 50) {
            golpearBalon(jugadorOrigen, destino, 1, true);
        } else {
            golpearBalon(jugadorOrigen, destino, 1, true);
        }
    }

    private int elMasCercanoAlBalon(double yMaximoDelJugador) {

        int jugadorCercano = jugadorConMenorIteraciones(yMaximoDelJugador);
        if (jugadorCercano != -1) {
            return jugadorCercano;
        } else {
            int[] jugadores = Util.getInfoMasCercano(sp.misJugadores(), balonSiguiente.posicion, new ArrayList(), false);
            return jugadores[0];
        }
    }



    private Posicion getPosicionMarca(int rival, double corrimiento) {
        Posicion p1 = balonSiguiente.posicion;
        Posicion p2 = sp.rivales()[rival];

        if (corrimiento < 0) { //atras entonces me paro entre el rival y el arco
            p1 = Constantes.centroArcoInf;
            corrimiento *= -1;
        }

        Posicion result = new Posicion();
        double y = getYParaMarcar(p1.getX(), p1.getY(), p2.getX(), p2.getY(), corrimiento);
        double x = getXOptimo(p1.getX(), p1.getY(), p2.getX(), p2.getY(), y);
        result = result.setPosicion(x, y);
        return result;
    }

    private Posicion getPosicionMolestarGolero(){
        Posicion result = posicionAtaque[9];
        if (! sp.sacaRival()) {
            int goleroRival = Util.getGoleroRival(sp);
            Posicion pGoleroRival = sp.rivales()[goleroRival];
            if (pGoleroRival.distancia(Constantes.centroArcoSup) < 8) {
                result = new Posicion(pGoleroRival.getX(), pGoleroRival.getY() - 5);
            }
        }
        return result;
    }

    private Posicion getPaloOpuesto(){
        Posicion result = null;
        int goleroRival = Util.getGoleroRival(sp);
        Posicion pGoleroRival = sp.rivales()[goleroRival];

        double distancia = sp.balon().distancia(Constantes.centroArcoSup);
        double rematarAMetrosDelPalo = 1;
        if (distancia > 20){
            rematarAMetrosDelPalo = 2; //mas al medio
        }

        if (pGoleroRival.distancia(Constantes.posteDerArcoSup) < pGoleroRival.distancia(Constantes.posteIzqArcoSup)) {
            result = new Posicion(Constantes.posteIzqArcoSup);
            result = result.moverPosicion(rematarAMetrosDelPalo, 0);
        }else{
            result = new Posicion(Constantes.posteDerArcoSup);
            result = result.moverPosicion(-1*rematarAMetrosDelPalo, 0);
        }
        return result;
    }

    private Posicion getPosicionOptima(int jugador) {

        Posicion p1 = balonSiguiente.posicion;
        Posicion p2 = normal[jugador];

        Posicion result = new Posicion();
        double y = getYParaMarcar(p1.getX(), p1.getY(), p2.getX(), p2.getY(), getAdelantamiento(jugador));
        double x = getXOptimo(p1.getX(), p1.getY(), p2.getX(), p2.getY(), y);
        result = result.setPosicion(x, y);
        return result;
    }

    private int[] ordenarPorMenorY(Posicion[] posiciones) {
        ArrayList<Jugador> contrarios = new ArrayList<Jugador>(11);
        for (int i = 0; i <= 10; i++) {
            Jugador j = new Jugador(i, posiciones[i]);
            contrarios.add(j);
        }
        Collections.sort(contrarios, new ComparadorContrarios());

        int[] result = new int[11];
        for (int i = 0; i <= 10; i++) {
            result[i] = contrarios.get(i).id;
        }
        return result;
    }

    private double getXOptimo(double x1, double y1, double x2, double y2, double nuevoY) { /*pronto*/
        double m = (x1 - x2) / (y1 - y2);
        return (m * (nuevoY - y2)) + x2;
    }

    private double getYParaMarcar(double x1, double y1, double x2, double y2, double distancia) {/*pronto*/
        double result = 0;
        if (Math.abs(y1 - y2) > 5) {
            if (y1 > y2) {
                result = y2 + distancia;
            } else {
                result = y2 - distancia;
            }
        } else {
            result = y2;
        }
        return result;
    }

    private int getMiJugadorMasCerca(int contrario, ArrayList excluir) {
        int dev1[] = Util.getInfoMasCercano(sp.misJugadores(), sp.rivales()[contrario], excluir, false);
        return dev1[0];
    }

    private int getJugadorPase(int jugadorOrigen) {
        int result = -1;
        ArrayList<PuntosPase> puntosPase = new ArrayList<PuntosPase>();

        int jugadorAdelante = Util.getInfoMasCercano(sp.rivales(), sp.misJugadores()[jugadorOrigen], new ArrayList(), true)[0];
        int jugador = Util.getInfoMasCercano(sp.rivales(), sp.misJugadores()[jugadorOrigen], new ArrayList(), false)[0];

        if ((jugadorAdelante == -1 || distanciaAlContrario(jugadorOrigen, jugadorAdelante) > 17) &&
                distanciaAlContrario(jugadorOrigen, jugador) > (Constantes.DISTANCIA_CONTROL_BALON + 0.5)) {
            if (posicionAutoPase(jugadorOrigen) != null) {
                result = jugadorOrigen;
            }
        }

        for (int i = 1; i < 11; i++) {
            puntosPase.add(new PuntosPase(i, getPuntosPase(jugadorOrigen, i)));
        }
        Collections.sort(puntosPase, new ComparadorPuntosPase());
        if (result != -1) { //tenemos auto pase asegurado
//            if (puntosPase.get(9).puntos < 8 || jugadorOrigen >= 8){ //si no tenemos un pase muy bueno vamos por el autopase
                return result; //vamos por el autopase
//            }
        }
        boolean primerPase = true;
        for (int i = 9; i >= 0; i--) {
            PuntosPase pp = puntosPase.get(i);
            if (sp.misJugadores()[pp.jugador].getY() > -25) {
                if (!primerPase || !iteracionFound) {
                    return pp.jugador;
                } else {
                    primerPase = false;
                }
            }
        }

        if (jugadorOrigen == 8 || jugadorOrigen == 9){
            result = 10;
        }

        return result;
    }

    private int getPuntosPase(int jugadorOrigen, int jugadorDestino) {
        //puntos por la distancia
        int result = 0;
        double d = distanciaEntreMisJugadores(jugadorOrigen, jugadorDestino);
        if (d > 10 && d < 30) {
            result += 2;
        }
        if (d >= 30) {
            result += 3;
        }
        //puntos por distancia al contrario
        d = distanciaAlContrarioMasCercano(jugadorDestino);
        if (d > 20){
            result += 6;
        }else if (d > 10){
            result += 4;
        }else if (d > 4){
            result += 2;
        }
        //puntos si esta adelante
        if (sp.misJugadores()[jugadorOrigen].getY() < sp.misJugadores()[jugadorDestino].getY()) {
            result += 10;
        }
        //puntos por cercania al arco
        d = sp.misJugadores()[jugadorDestino].distancia(Constantes.centroArcoSup);
        if (d < 35) {
            result += 3;
        }
        //puntos por distancia del contrario a la trayectoria
        d = Util.getDistanciaJugadorMasCercaAlSegmento(sp.rivales(), sp.misJugadores()[jugadorOrigen], sp.misJugadores()[jugadorDestino]);
        if (d > 10) {
            result += 3;
        } else if (d > 3) {
            result += 1;
        } else {
            result -= 3;
        }

        //puntos por diferencia de y, para evitar pases derechos al frente donde en general viene un defensa
        if (Math.abs(sp.misJugadores()[jugadorOrigen].getY() - sp.misJugadores()[jugadorDestino].getY()) > 3) {
            result += 2;
        }
        return result;
    }

    private double distanciaEntreMisJugadores(int i, int j) {
        return sp.misJugadores()[i].distancia(sp.misJugadores()[j]);
    }

    private double distanciaAlContrario(int i, int j) {
        return sp.misJugadores()[i].distancia(sp.rivales()[j]);
    }

    private double distanciaAlContrarioMasCercano(int i) {
        return distanciaAlContrario(i, contrarioMasCercano(i));
    }

    private boolean puedeSerGol(int jugador) {
        Posicion p = sp.misJugadores()[jugador];
        boolean result = p.distancia(Constantes.centroArcoSup) <= 30;

//        if (result){
//            //veamos si tengo un hombre en el area solo solito
//            int miPosibleGoleador = getMiJugadorMasCerca(Util.getGoleroRival(sp), null);
//            if (miPosibleGoleador != jugador){
//                if(distanciaAlContrarioMasCercano(miPosibleGoleador) > 5){
//                    result = false;
//                }
//            }
//        }
        if(result){
            if ((p.getY() > 40) && (Math.abs(p.getX()) > 18)) {
                result = false;
            }
        }
        return result;
    }

    private void moverJugador(int jugador, Posicion p) {
        if (Util.dentroCampo(p)) {
            comandos.add(new ComandoIrA(jugador, p));
        } else {
            comandos.add(new ComandoIrA(jugador, normal[jugador]));
        }
    }

    private void golpearBalon(int jugador, Posicion destinoBola, double fuerzaRemate, boolean remateAlto) {

        if (!sp.saco() || this.distanciaAlContrarioMasCercano(jugador) > (Constantes.DISTANCIA_SAQUE-4)) {
            comandos.add(new ComandoGolpearBalon(jugador, destinoBola, fuerzaRemate, remateAlto));
        }
    }

    private void golpearBalon(int jugador, Posicion destinoBola, double fuerzaRemate, double anguloVertical) {

        if (!sp.saco() || this.distanciaAlContrarioMasCercano(jugador) > (Constantes.DISTANCIA_SAQUE-4)) {
            comandos.add(new ComandoGolpearBalon(jugador, destinoBola, fuerzaRemate, anguloVertical));
        }
    }

    private Posicion reventarBalon(int jugador) {
        boolean adelante = false;
        boolean derechaAdelante = false;
        boolean izquierdaAdelante = false;
        boolean derecha = false;
        boolean izquierda = false;
        Posicion miJugador = sp.misJugadores()[jugador];
        Posicion rival = null;
        int[] distancias = miJugador.indicesMasCercanos(sp.rivales());
        for (int i = 0; i < distancias.length; i++) {
            rival = sp.rivales()[distancias[i]];
            if (distanciaAlContrario(jugador, distancias[i]) < 17) {
                adelante = adelante || (Math.abs(miJugador.getX() - rival.getX()) < 5 && rival.getY() >= miJugador.getY());
                derechaAdelante = derechaAdelante || (miJugador.getX() <= rival.getX() && rival.getY() >= miJugador.getY());
                izquierdaAdelante = izquierdaAdelante || (miJugador.getX() >= rival.getX() && rival.getY() >= miJugador.getY());
                derecha = derecha || (miJugador.getX() <= rival.getX() && rival.getY() <= miJugador.getY());
                izquierda = izquierda || (miJugador.getX() >= rival.getX() && rival.getY() <= miJugador.getY());
            }
        }
        Posicion destino = null;//miJugador.getX() < 0 ? Constantes.cornerInfIzq : Constantes.cornerInfDer;
        if (!adelante) {
            destino = new Posicion(sp.misJugadores()[Util.getInfoMasCercano(sp.misJugadores(), Constantes.centroCampoJuego)[0]]);
        } else if (!derechaAdelante) {
            destino = new Posicion(miJugador.getX() + 30, 0);
        } else if (!izquierdaAdelante) {
            destino = new Posicion(miJugador.getX() - 30, 0);
        } else if (!derecha) {
            destino = new Posicion(miJugador.getX() + 30, miJugador.getY());
        } else if (!izquierda) {
            destino = new Posicion(miJugador.getX() - 30, miJugador.getY());
        } else {
            destino = new Posicion(miJugador.getX() - 30, miJugador.getY());
        }
        return destino;
    }

    private void actualizarPosiciones() {
        posicionesFuturo = new ArrayList<Balon>();
        posicionesFuturo.add(Util.getSiguienteUbicacion(balonAnterior.posicion, sp.balon(), altura, dz, suelo));
        dz = posicionesFuturo.get(0).dz;
        suelo = posicionesFuturo.get(0).suelo;
        posicionesFuturo.add(Util.getSiguienteUbicacion(sp.balon(), posicionesFuturo.get(0).posicion, posicionesFuturo.get(0).altura, posicionesFuturo.get(0).dz, posicionesFuturo.get(0).suelo));
        for (int i = 2; i < Util.ITERACIONES_CRUZAR_BALON; i++) {
            posicionesFuturo.add(Util.getSiguienteUbicacion(posicionesFuturo.get(i - 2).posicion, posicionesFuturo.get(i - 1).posicion, posicionesFuturo.get(i - 1).altura, posicionesFuturo.get(i - 1).dz, posicionesFuturo.get(i - 1).suelo));
        }

    }

    private int contrarioMasCercano(int miJugador) {
        return Util.getInfoMasCercano(sp.rivales(), sp.misJugadores()[miJugador])[0];
    }

    private double getAdelantamientoMarca(boolean atras) {
        double result = 2;
        if (atras) {
            result = -1;
        }
        return result;
    }

    private double getAdelantamiento(int jugador) {

        double result = 5;
        if (jugador == 9){
            result = 0;
        }
        if (ataque){
            result = 0;
        }
        return result;
    }

    private int jugadorConMenorIteraciones(double yMaximoDelJugador) {
        int jugador = -1;
        int iteraciones = -1;
        int tmp;
        for (int i = 0; i < 11; i++) {
            tmp = Util.iteracionesCruzarBalon(posicionesFuturo, sp.misJugadores()[i], i);
            if (tmp != -1) {
                if (iteraciones == -1 || tmp < iteraciones) {
                    if (yMaximoDelJugador == -1 || sp.misJugadores()[i].getY() < yMaximoDelJugador) {
                        iteraciones = tmp;
                        jugador = i;
                    }
                }
            }
        }
        return jugador;
    }

    private int jugadorConMenorIteracionesSinSerGolero() {
        int jugador = -1;
        int iteraciones = -1;
        int tmp;
        for (int i = 1; i < 11; i++) {
            tmp = Util.iteracionesCruzarBalon(posicionesFuturo, sp.misJugadores()[i], i);
            if (tmp != -1) {
                if (iteraciones == -1 || tmp < iteraciones) {
                    iteraciones = tmp;
                    jugador = i;
                }
            }
        }
        if (jugador == -1){
            //mandamos al que esté más cerca sea como sea sin ser el golero
            ArrayList excluir = new ArrayList();
            excluir.add(sp.misJugadores()[0]);
            jugador = Util.getInfoMasCercano(sp.misJugadores(), balonSiguiente.posicion, excluir, false)[0];
        }
        return jugador;
    }

    private Posicion cruzarBalon(int jugador) {

        int iteracion = Util.iteracionesCruzarBalon(posicionesFuturo, sp.misJugadores()[jugador], jugador);
        Posicion p = iteracion == -1 ? null : posicionesFuturo.get(iteracion).posicion;

        if (p == null || !Util.dentroCampo(p)) {
            p = balonSiguiente.posicion;
        }
        return p;
    }

    private Posicion posicionAutoPase(int jugador) {
        Posicion result = null;

        Posicion miJugador = sp.misJugadores()[jugador];
        Posicion rival = null;
        int[] datosRival = Util.getInfoMasCercano(sp.rivales(), sp.misJugadores()[jugador], null, true);

        if (datosRival[1] < 15) {
            rival = sp.rivales()[datosRival[0]]; //mas cercano adelante
        } else {
            rival = sp.rivales()[contrarioMasCercano(jugador)]; //mas cercano
        }

        if (miJugador.distancia(rival) > 20) {
            result = new Posicion(Constantes.centroArcoSup);
        } else {
            result = new Posicion(miJugador);

            //por defecto avanzamos de a 2 metros hacia adelante
            double dx = 2;
            double dy = 2;

            if (rival.getX() >= miJugador.getX()){
                dx *= -1;
            }
            if (rival.getY()-5 >= miJugador.getY()){
                dy *= -1;
            }
            if (Math.abs(miJugador.getX() + dx) > (Constantes.ANCHO_CAMPO_JUEGO / 2 - 10)) {
                dx = 0;
            }
            if (Math.abs(miJugador.getY() + dy) > (Constantes.LARGO_CAMPO_JUEGO / 2 - 10)) {
                dy = 0;
            }

            result = result.moverPosicion(dx, dy);

            if (!Util.dentroCampo(result) || (dx == 0 && dy == 0)){
                result = null;
            }
        }
        return result;
    }

    private int golpeoElBalon(int[] iteraciones) {
        int result = -1;
        for (int i = 0; i < iteraciones.length; i++) {
            if (iteraciones[i] == Constantes.ITERACIONES_GOLPEAR_BALON) {
                result = i;
            }
        }
        return result;
    }

    private boolean evitarCicloDePases() {
        boolean iteracion = false;

        int jugadorQueGolpeoElBalon = golpeoElBalon(sp.iteracionesParaRematar());

        if (jugadorQueGolpeoElBalon != -1) {
            if (ultimosDosJugadores[0][0] == jugadorQueGolpeoElBalon) {
                ultimosDosJugadores[0][1] = ultimosDosJugadores[0][1] + 1;
            } else if (ultimosDosJugadores[1][0] == jugadorQueGolpeoElBalon) {
                ultimosDosJugadores[1][1] = ultimosDosJugadores[1][1] + 1;
            } else {
                ultimosDosJugadores[0][0] = ultimosDosJugadores[1][0];
                ultimosDosJugadores[0][1] = ultimosDosJugadores[1][1];
                ultimosDosJugadores[1][0] = jugadorQueGolpeoElBalon;
                ultimosDosJugadores[1][1] = 1;
            }
        } else {//le pego un rival
            if (golpeoElBalon(sp.iteracionesParaRematar()) != -1) {
                ultimosDosJugadores[0][0] = -1;
                ultimosDosJugadores[0][1] = 0;
                ultimosDosJugadores[1][0] = -1;
                ultimosDosJugadores[1][1] = 0;
            }
        }
        if (ultimosDosJugadores[0][1] > 3 && ultimosDosJugadores[1][1] > 3) {
            iteracion = true;
        }

        return iteracion;
    }
}
class PuntosPase {

    public int jugador;
    public int puntos;

    public PuntosPase(int jugador, int puntos) {
        this.jugador = jugador;
        this.puntos = puntos;
    }
}

class ComparadorPuntosPase implements Comparator {

    public int compare(Object o1, Object o2) {
        int result = new Integer(((PuntosPase) o1).puntos).compareTo(new Integer(((PuntosPase) o2).puntos));
        return result;
    }
}